# from chapter 2.1.5

np.array([3.14, 4., 2., 3])
np.array([range(i, i+3) for i in [2, 4, 6]])

import numpy as np
np.zeros(10, dtype=int)
np.ones((3, 5), dtype=float)
np.full((3, 5), 3.14)
np.arange(0, 20, 2)
np.linspace(0, 1, 5)  # 5个元素，均匀分配到0~1
np.random.random((3, 3))  # 0~1均匀分布
np.random.normal(0, 1, (3, 3))  # 0~1正态分布
np.random.randint(0, 10, (3, 3))  # [0,10)之间整数
np.eye(3) #3*3单位矩阵
np.empty(3) #三个整型组成的未初始化数组

np.zeros(10, dtype=np.int16)

np.random.seed(0)
x1=np.random.randint(10, size=6)
x2=np.random.randint(10, size=(3, 4))
x3=np.random.randint(10, size=(3, 4, 5))
# 每个数组有ndim，shape，size三个属性，即数组的维度、每个维度的大小、数组的总大小，如x3：ndim=3,shape=(3,4,5),size=60

#切片[start:stop:step]
x=np.arange(10)
x[:5] #前5
x[5:] #5之后
x[4:7]
x[::2]
x[::-1] #逆序
x[5::-2]

x2[:2, :3] #2行，3列
x2[:3, ::2] #所有3行，每隔1列
x2[:, 0] #所有行，第1列
x2[0, :] #第1行，所有列
x2[0] # == x2[0,:]

grid=np.arange(1, 10).reshape((3, 3))
x=np.array([1, 2, 3])
x.reshape((1, 3)) #通过变形获得行向量
x[np.newaxis, :] #通过newaxis获得
x.reshape((3, 1)) #通过变形获得列向量
x[:, np.newaxis] #通过newaxis获得

x=np.array([1, 2, 3])
y=np.array([3, 2, 1])
np.concatenate([x, y]) #拼接
z=[99, 99, 99]
print(np.concatenate([x, y, z]))

grid=np.array([[1, 2, 3],
               [4, 5, 6]])
np.concatenate([grid, grid]) #二维数组按行拼接
np.concatenate([grid, grid], axis=1) #沿着第2个轴拼接（从0索引）

x=np.array([1, 2, 3])
grid=np.array([[9, 8, 7],
               [6, 5, 4]])
np.vstack([x, grid]) #垂直栈数组
y=np.array([[99],
            [99]])
np.hstack([grid, y]) #水平栈数组

# The opposite of concatenation is splitting
x=[1, 2, 3, 99, 99, 3, 2, 1]
x1, x2, x3=np.split(x, [3, 5]) #索引列表记录的是分裂点的位置
print(x1, x2, x3) #N分裂点得到N+1个数组

grid=np.arange(16).reshape((4, 4))
upper, lower=np.vsplit(grid, [2])
left, right=np.hsplit(grid, [2])
#np.dsplit将数组沿着第3个维度分裂

theta=np.linspace(0, np.pi, 3)
print("theta = ", theta)
print("sin(theta) = ", np.sin(theta))
print("cos(theta) = ", np.cos(theta))
print("tan(theta) = ", np.tan(theta))
x=[-1, 0, 1]
print("x = ", x)
print("arcsin(x) = ", np.arcsin(x))
print("arccos(x) = ", np.arccos(x))
print("arctan(x) = ", np.arctan(x))
x = [1, 2, 3]
print("x =", x)
print("e^x =", np.exp(x))
print("2^x =", np.exp2(x))
print("3^x =", np.power(3, x))
x = [1, 2, 4, 10]
print("x =", x)
print("ln(x) =", np.log(x))
print("log2(x) =", np.log2(x))
print("log10(x) =", np.log10(x))

#高级通用函数特性：
#指定输出
#聚合
#外积

L=np.random.random(100)
np.sum(L)
np.min(L)
np.max(L)
L.sum()

M=np.random.random((3, 4))
M.sum() #返回整个数组的聚合结果
M.min(axis=0) #指定沿axis=0，即每列
M.max(axis=1) #指定每行
# axis关键字指定的是数组将会被折叠的维度，而不是将要返回的维度

import pandas as pd
data=pd.read_csv('~/hrepos/notes/PythonDataScienceHankbook/president_heights.csv')
heights=np.array(data['height(cm)'])
print("Mean height: ", heights.mean())
print("Standard deviation:", heights.std())
print("Minimum height: ", heights.min())
print("Maximum height: ", heights.max())
print("25th percentile: ", np.percentile(heights, 25))
print("Median:", np.median(heights))
print("75th percentile:", np.percentile(heights, 75))

import matplotlib.pyplot as plt
import seaborn; seaborn.set()
# plt.hist(heights)
# plt.title('Height Distribution of US Presidents')
# plt.xlabel('height (cm)')
# plt.ylabel('number');

a=np.array([0, 1, 2])
a + 5
M=np.ones((3, 3))
M + a

a=np.arange(3)
b=np.arange(3)[:, np.newaxis]
a + b

# 规则 1:如果两个数组的维度数不相同,那么小维度数组的形状将
# 会在最左边补 1。
M=np.ones((2, 3))
a=np.arange(3)
# a的维度被补为(1, 3), 最终为(2, 3)

# 规则 2:如果两个数组的形状在任何一个维度上都不匹配,那么数
# 组的形状会沿着维度为 1 的维度扩展以匹配另外一个数组的形状。
a=np.arange(3).reshape((3, 1))
b=np.arange(3)
# b扩展为(1, 3)，与a同时补全为(3, 3)

# 规则 3:如果两个数组的形状在任何一个维度上都不匹配并且没有
# 任何一个维度等于 1,那么会引发异常。
M=np.ones((3, 2))
a=np.arange(3)
# 因只可在左侧补全，不可在右侧，此时报错。
# 可作变换，将a转换为(3, 1)：
M + a[:, np.newaxis]
np.logaddexp(M, a[:, np.newaxis])

X=np.random.random((10, 3))
Xmean=X.mean(0) #0为第一个维度, 1为第二个
X_centered=X - Xmean #维度为(10, 3) - (1, 3)

x=np.linspace(0, 5, 50)
y=np.linspace(0, 5, 50)[:, np.newaxis]
z=np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x)
import matplotlib.pyplot as plt
plt.imshow(z, origin='lower', extent=[0, 5, 0, 5], cmap='viridis')
plt.colorbar()

x=np.array([1, 2, 3, 4, 5])
x > 3 # np.greater(3), Out: dtype=bool
x <= 3
x != 3
(2 * x)==(x ** 2)

rng=np.random.RandomState(0)
x=rng.randint(10, size=(3, 4))
x < 6 # Out: dtype=bool
np.count_nonzero(x < 6) # 与下一行结果相同
np.sum(x<6) #F==0, T==1
np.sum(x < 6, axis=1) #按轴折叠，分别求和
np.any(x > 8)
np.all(x < 0)
np.all(x < 8, axis=1) # dtype=bool
# 可加入逻辑运算，& and, | or, ^ xor, ~ not

x[x < 5] #掩码
# and 和 or 判断整个对象是真或假,而 & 和 | 是指每个对象中的比特位
A = np.array([1, 0, 1, 0, 1, 0], dtype=bool)
B = np.array([1, 1, 1, 0, 1, 1], dtype=bool)
A | B
A or B # Error

# 花哨的索引，意味着传递一个索引数组来一次性获得多个数组元素
rand=np.random.RandomState(42)
x=rand.randint(100, size=10)
[x[3], x[7], x[2]] # != x[[3], [7], [2]]
ind=np.array([[3, 7],
              [4, 5]])
x[ind]
# 结果的形状与索引数组的形状一致,而不是与被索引数组的形状一致

X=np.arange(12).reshape((3, 4))
row=np.array([0, 1, 2])
col=np.array([2, 1, 3])
X[row, col] # [[0,2], [1,1], [2,3]]

X[row[:, np.newaxis], col]
# [[0,2], [0,1], [0,3]
#  [1,2], [1,1], [1,3]
#  [2,2], [2,1], [2,3]]
# 返回的值反映的是广播后的索引数组的形状,而不是被索引的数组的形状

X[2, [2, 0, 1]]
X[1:, [2, 0, 1]]
mask=np.array([1, 0, 1, 0], dtype=bool)
X[row[:, np.newaxis], mask]

# N*D 的矩阵
mean=[0, 0]
cov=[[1, 2],
     [2, 5]]
X=rand.multivariate_normal(mean, cov, 100)
X.shape
indices=np.random.choice(X.shape[0], 20, replace=False)
selection=X[indices]
selection.shape
plt.scatter(X[:, 0], X[:, 1], alpha=0.3)
plt.scatter(selection[:, 0], selection[:, 1],
            facecolor='none', edgecolor='b', s=200);

x=np.arange(10)
i=np.array([2, 1, 8, 4])
x[i]=99
x[i] -= 10

i=[2, 3, 3, 4, 4, 4]
x[i] += 1
x=np.zeros(10)
np.add.at(x, i, 1)

np.random.seed(42)
x=np.random.randn(100)
bins=np.linspace(-5, 5, 20)
counts=np.zeros_like(bins)
i=np.searchsorted(bins, x)
np.add.at(counts, i, 1)
plt.plot(bins, counts, linestyle='steps')

plt.hist(x, bins, histtype='step')

import numpy as np

def selection_sort(x):
    for i in range(len(x)):
        swap = i + np.argmin(x[i:])
        (x[i], x[swap]) = (x[swap], x[i])
    return x

x=np.array([2, 1, 4, 3, 5])
selection_sort(x)

def bogosort(x):
    while np.any(x[:-1] > x[1:]):
        np.random.shuffle(x)
    return x

x=np.array([2, 1, 4, 3, 5])
bogosort(x)

x=np.array([2, 1, 4, 3, 5])
np.sort(x) #不修改原始数据
x.sort() #替代原始数据

rand=np.random.RandomState(42)
X=rand.randint(0, 10, (4, 6))
np.sort(X, axis=0)
np.sort(X, axis=1)

x=np.array([7, 2, 3, 1, 6, 5, 4])
np.partition(x, 3) #最左边是最小的3个值，结果中两段都是任意排列的。

np.partition(X, 2, axis=1)

X=rand.rand(10, 2)

import matplotlib.pyplot as plt
import seaborn; seaborn.set() # 设置画图风格
plt.scatter(X[:, 0], X[:, 1], s=100)

name = ['Alice', 'Bob', 'Cathy', 'Doug']
age = [25, 45, 37, 19]
weight = [55.0, 85.5, 68.0, 61.5]

data = np.zeros(4, dtype={'names':('name', 'age', 'weight'),
                          'formats':('U10', 'i4', 'f8')})
# U10: 长度不超过10的Unicode
# i4: 4字节(32比特)整型
# f8: 8字节(64比特)浮点型
print(data.dtype)

data['name'] = name
data['age'] = age
data['weight'] = weight

data['name']
data[0]
data[-1]['name']

data[data['age'] < 30]['name'] #年龄小于30的人名字

np.dtype({'names':('name', 'age', 'weight'),
          'formats':((np.str_, 10), int, np.float32)})
# dtype指定数据类型

tp = np.dtype([('id', 'i8'), ('mat', 'f8', (3, 3))])
X = np.zeros(1, dtype=tp)
print(X[0])
print(X['mat'][0])
